package com.yyw.gulimall.elasticsearch.test.completable;

import com.alibaba.druid.support.json.JSONUtils;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 易煜玮
 * @ClassName Completable01.java
 * @Description CompletableFuture 异步编排测试
 * 下面所有带Async的方法都是自己规定线程池，我们这里统一使用自己规定线程池
 * @createTime 2020年12月06日 18:43:00
 */
public class Completable01 {
    /**
     * 创建一个固定活跃线程数的线程
     */
    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    /**
     * 测试 whenCompleteAsync() / whenComplete()
     * 可以拿到上一步的返回结果和异常信息  但是无返回值
     * exceptionally()
     * 可以拿到上一步的错误，并且可以返回默认值，一般搭配whenCompleteAsync()一起使用
     *
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main1(String[] args) throws ExecutionException, InterruptedException {
        // 使用supplyAsync()创建一个异步任务，有返回值的
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            return i;
        }, executor).whenCompleteAsync((result, e) -> {
            if (null != e) {
                // 不管有没有异常，都会执行这个方法，所以要做异常判断,直接去下面的方法
                return;
            }
            System.out.println("操作成功,结果等于:" + result);
            // 执行其他的业务逻辑...
        }, executor).exceptionally(e -> {
            // 如果发生了错误
            System.out.println("发生了错误:" + e);
            return 10;
        });
        System.out.println(future.get());
    }

    /**
     * handleAsync()/handle()
     * 可以拿到返回结果和异常。同时还可以对结果进行二次处理。有返回值，
     * 是whenCompleteAsync和exceptionally的结合体
     *
     * @param args
     */
    public static void main2(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            return i;
        }).handleAsync((result, e) -> {
            if (null != e) {
                // 出现异常,返回默认值
                System.out.println("出现了异常:" + e);
                return 10;
            }
            System.out.println("执行成功,结果为:" + result);
            return result * 2;
        }, executor);
        System.out.println("最终的结果: " + future.get());
    }


    /**
     * thenRunAsync()/thenRun() 没有返回值
     * 线程串行化，拿不到上一步的返回值，自己也不能返回
     * 要做异常处理，exceptionally(ex) 放在最后面
     *
     * @param args
     */
    public static void main3(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            try {
                System.out.println("我开始休眠咯");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return i;
        }, executor).thenRunAsync(() -> {
            System.out.println("执行第二部，我拿不到上一步返回值。我自己也不返回");
        }, executor).exceptionally(throwable -> {
            System.out.println("发生了异常:" + throwable);
            return null;
        });
    }

    /**
     * 测试 thenAcceptAsync()/thenAccept()
     * 可以拿到上一步的返回值，但是自身没有返回值
     * 要捕捉所有的异常可以用 exceptionally() 并且放在最后面
     * @param args
     */
    public static void main4(String[] args) {
        CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            return i;
        }, executor).exceptionally(e -> {
            System.out.println("发生了错误:" + e);
            return -1;
        }).thenAcceptAsync(result -> {
            int i = 10 / 0;
            System.out.println("我能拿到上一步的返回值: " + result + "但是我没有返回值");
        }, executor).exceptionally(e -> {
            System.out.println(e);
            return null;
        });
    }


    /**
     * thenApplyAsync()/thenApply()
     * 可以拿到上一步的返回值，并且自身还能返回，可以对上一步的结果做二次处理
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main5(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 0;
            return i;
        }).thenApplyAsync(result -> {
            System.out.println("我拿到上一步的返回值啦：" + result + "，并且我自己还能再返回");
            return result * 2;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常: " + e);
            return -1;
        });
        System.out.println("最终的结果: " + future.get());
    }

    /**
     * thenAcceptBothAsync()
     * 必须都执行完毕
     * 两个异步任务同时执行，可以获取到两个任务的返回值，自己没有返回值
     * @param args
     */
    public static void main6(String[] args) {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一: 我开始执行了");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第一个任务,我执行完了";
            System.out.println("任务一：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值1";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("任务二：我开始执行了");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第二个任务,我执行完了";
            System.out.println("任务二：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值2";
        });

        future1.thenAcceptBothAsync(future2, (f1, f2) -> {
            System.out.println("我拿到了两个方法的返回结果啦：" + f1 +  " ===== " + f2);
        }, executor);
    }

    /**
     * thenCombineAsync
     * 必须都执行完毕
     * 两个异步任务同时执行，可以获取到两个任务的返回值，而且自己还能再次返回，对结果做二次处理
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main7(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一: 我开始执行了");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第一个任务,我执行完了";
            System.out.println("任务一：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值1";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("任务二：我开始执行了");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第二个任务,我执行完了";
            System.out.println("任务二：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值2";
        });

        CompletableFuture<String> future = future1.thenCombineAsync(future2, (f1, f2) -> {
            System.out.println("我拿到了两个方法的返回结果啦：" + f1 + " ===== " + f2);
            return f1 + "===" + f2;
        }, executor);

        System.out.println("最终的结果:" + future.get());
    }


    /**
     * xxxEitherAsync 两个异步任务执行，都是只接受一个返回结果，谁执行的快，就用谁的执行结果。这里只举例一个
     * applyToEitherAsync  两个异步任务执行，能接受上一个方法的结果，同时自生还能返回，对结果做二次处理
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main8(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一: 我开始执行了");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第一个任务,我执行完了";
            System.out.println("任务一：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值1";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("任务二：我开始执行了");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第二个任务,我执行完了";
            System.out.println("任务二：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值2";
        });

        // 只接受一个返回值，谁执行的快，谁最先进来
        CompletableFuture<String> future = future1.applyToEitherAsync(future2, (result) -> {
            System.out.println("我拿到了最快的方法的返回结果啦：" + result);
            return result + "===》这是最快的操作";
        }, executor);

        System.out.println("最终的结果:" + future.get());
    }

    /**
     * allOf
     * 组合多个任务，等待所有任务都执行结束后才执行后面的逻辑
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main9(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一: 我开始执行了");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第一个任务,我执行完了";
            System.out.println("任务一：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值1";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("任务二：我开始执行了");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第二个任务,我执行完了";
            System.out.println("任务二：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值2";
        });

        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 4;
            return i;
        }, executor);

        // 组合多任务
        CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2, future3);
        // 必须执行次操作.等待全部的执行结果,否则执行快的线程执行完后会直接执行下面的代码，就无法做到异步编排了
        all.get();
        // 获取结果
        System.out.println(future1.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
    }

    /**
     * anyOf()
     * 组合多个任务，只获取最快执行完毕的任务结果，只等待第一个完毕的任务
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务一: 我开始执行了");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第一个任务,我执行完了";
            System.out.println("任务一：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值1";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                System.out.println("任务二：我开始执行了");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String str = "我是第二个任务,我执行完了";
            System.out.println("任务二：我执行好了");
            return str;
        }, executor).exceptionally(e -> {
            System.out.println("发生了异常：" + e);
            return "我是默认值2";
        });

        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 4;
            return i;
        }, executor);

        // 组合多任务
        CompletableFuture<Object> all = CompletableFuture.anyOf(future1, future2, future3);
        // 必须执行次操作.等待全部的执行结果,否则执行快的线程执行完后会直接执行下面的代码，就无法做到异步编排了
        System.out.println("最快执行完的是：================》" + all.get());
        // 获取结果
        System.out.println(future1.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
    }
}
